#-*- coding:utf-8 -*-

# The MIT License (MIT)
# 
# Copyright (c)  2014  Li Lin  <jzqlin@gmail.com>
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

from UAFramework import gen_token


class Login(object):
    """Base class for login and login session authenticate"""
    
    # Error codes
    E_LOGIN_OK = 0
    E_NOT_REGISTER = -300    
    E_PASSWORD_INVALID = -301
    E_NOT_VERIFIED = -302
    
    E_AUTH_OK = 0
    E_LOGIN_SESSION_NOT_FOUND = -303
    E_SESSION_KEY_INVALID = -304
        
    # login session expired time, developers can modify        
    SESSION_EXPIRED_TIME = 144000
    
        

class BasicLogin(Login):
    """User login by providing account and password"""    
    
    
    @staticmethod
    def configure_cache(redis_client):
        """We use redis server to store the user's login session, so we need to set a 
        redis client object. 
        """              
        BasicLogin.redis_client = redis_client
        
                    
    
    def __init__(self, ua_user_basic_databases, ua_user_basic_classes):
        self.ua_user_basic_databases = ua_user_basic_databases
        self.ua_user_basic_classes = ua_user_basic_classes
        self.redis_cleint = BasicLogin.redis_cleint                
    
        
    def login(self, account, password):
        """Login with account and password.
        Return error code if this is something wrong, or return a tuple if login successfully.
        """
        session = self.ua_user_basic_databases.get_session(account)
        
        UserBasic = self.ua_user_basic_classes.get_class(account) 
        user = session.query(UserBasic).filter(UserBasic.account == account).first()
        if user == None:
            return Login.E_NOT_REGISTER
        
        if user.verified == 0:
            return Login.E_NOT_VERIFIED
        
        if user.password != password:
            return Login.E_PASSWORD_INVALID
        
        session_key = self.redis_client.get(account)
        if session_key != None:
            # warning: user login already, the session_key will be replaced
            pass
        
        session_key = gen_token()
        # ex: set expired seconds, default 144000 seconds which is 4 hour
        self.redis_client.set(account, session_key, ex = Login.SESSION_EXPIRED_TIME)
        
        return (Login.E_LOGIN_OK, session_key, user)

        
       
class LoginSessionAuth(Login):
    """Authenticate user's session key in any scenario need to check the user's
    login session.
    """
    
    redis_cleint = None
    
    @staticmethod
    def configure_cache(redis_client):   
        """We use redis server to store the user's login session, so we need to set a 
        redis client object. 
        """      
        LoginSessionAuth.redis_cleint = redis_client
       

    def __init__(self):
        self.redis_cleint = LoginSessionAuth.redis_cleint
    

    def authenticate(self, account, session_key):
        """Authenticate user's session key, update the expired time of the session
        if the session key is right. 
        """
        
        key = self.redis_cleint.get(account)
        if key == None:
            return Login.E_LOGIN_SESSION_NOT_FOUND
        
        if key != session_key:
            return Login.E_SESSION_KEY_INVALID
        
        if key == session_key:
            # update expired seconds,default 144000 seconds which is 4 hour
            self.redis_client.set(account, session_key, ex = Login.SESSION_EXPIRED_TIME)
            return Login.E_AUTH_OK
        
    
